<?php

use think\Exception;
class SwooleWebsocket
{
	private $server;
	protected $websocket_host  = '0.0.0.0';
	protected $websocket_port  = 4431;
	protected $task_worker_num = 30;
	protected $log_file        = __DIR__.'/server.log';
	private $user              = null;

	public function __construct()
	{
		$this->server = new swoole_websocket_server($this->websocket_host, $this->websocket_port, SWOOLE_PROCESS, SWOOLE_SOCK_TCP | SWOOLE_SSL);
		$this->server->set([
			'daemonize'       => true,
			'pid_file'        => __DIR__.'/server.pid',
			'task_worker_num' => $this->task_worker_num,
			'ssl_cert_file'   => '/etc/nginx/cert/213984411530979.pem',
			'ssl_key_file'    => '/etc/nginx/cert/213984411530979.key',
    		//'open_http2_protocol' => true,
			]);
		$port = $this->server->listen($this->websocket_host, 9503, SWOOLE_SOCK_TCP);
		//$port->set();
		// $port->on('connect', function ($serv, $fd){
		//     echo "Client:" . $fd . " Connect.\n";
		// });
		
		$port->on('receive', function ($serv, $fd, $reactor_id, $data) {
			echo "[#".$serv->worker_id."]\tClient[$fd]: $data\n";
		});

		if ($this->log_file) {
			$this->server->set(['log_file' => $this->log_file]);
		}

		$this->server->on('Connect', array($this, 'onConnect'));
		$this->server->on('Message', array($this, 'onMessage'));
		$this->server->on('Open', array($this, 'onOpen'));
		$this->server->on('Close', array($this, 'onClose'));
		$this->server->on('Task', array($this, 'onTask'));
		$this->server->on('Finish', function() {});
		$this->server->on('HandShake', array($this, 'onHandShake'));
		$this->server->start();
	}

	public function onOpen(swoole_websocket_server $server, swoole_http_request $req)
	{
		foreach($server->connections as $fd)
		{
	        //$server->push($fd, json_encode($req->get)); 
		}
	}

	public function onClose(swoole_websocket_server $server, int $fd, int $reactorId)
	{
		try {
			unset($this->user[$fd]);			
			foreach($server->connections as $f)
			{
				$fd != $f ? $server->push($f, $fd . ':offline...') : ''; 
			}
			
		} catch (\Exception $e) {
			
		}
		
	}

	public function onTask($serv, $taskId, $workerId, $data)
	{
		//echo "Task Callback: " . $data;
	}

	public function onHandShake(swoole_http_request $request, swoole_http_response $response)
	{
		if(false){
			$response->end();
			return false;
		}
		  //websocket握手连接算法验证
		if(0 === preg_match('#^[+/0-9A-Za-z]{21}[AQgw]==$#', $request->header['sec-websocket-key']) || 16 !== strlen(base64_decode($request->header['sec-websocket-key']))){
			$response->end();
			return false;
		}
		// 
		$response->header('Upgrade','websocket'); 
		$response->header('Connection','Upgrade'); 
		$websocketStr = $request->header['sec-websocket-key'].'258EAFA5-E914-47DA-95CA-C5AB0DC85B11'; 
		$SecWebSocketAccept = base64_encode(sha1($websocketStr,true)); 
		$response->header('Sec-WebSocket-Accept', $SecWebSocketAccept); 
		$response->header('Sec-WebSocket-Version','13'); 
		$response->status(101);
		$response->end();
		echo "connected!" . PHP_EOL;
		return true;
	}

	public function onConnect(swoole_websocket_server $server, $request, $f)
	{
		try {
			$server->task($request);
			//$res = model('users')->find();
			foreach($server->connections as $fd)
			{
				if ($fd != $request) {
					$server->push($fd, $request . ':online...'); 
				}
			}
			
		} catch (\Exception $e) {
			
		}
		
	}

	public function onMessage(swoole_websocket_server $server, $frame)
	{
		try {
			$data = json_decode($frame->data, true);
			if (!is_array($data)) {
				throw new Exception("data error", 4431);				
			}
			$this->user[$frame->fd] = $data;
			$d = $this->multi_array_sort($this->user, 'score', SORT_DESC);
			$s = '';
			foreach ($d as $key => $value) {
				$s .= $key+1 ." 玩家：".$value['username']." 分数：".$value['score']."\n";
			}
			foreach($server->connections as $fd)
			{
				$server->push($fd, $s);
			}
			
		} catch (\Exception $e) {
			
		}
		
	}
	
	public function index()
	{
		$this->server->start();
	}

	protected function multi_array_sort($multi_array, $sort_key, $sort = SORT_ASC){ 
		if(is_array($multi_array)){ 
			foreach ($multi_array as $row_array){ 
				if(is_array($row_array)){ 
					$key_array[] = $row_array[$sort_key]; 
				}else{ 					
					return false; 
				} 
			} 
		}else{ 
			return false; 
		} 
		array_multisort($key_array,$sort,$multi_array); 
		return $multi_array; 
	}
}